SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
2.6 KB · 62 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import Link from 'next/link';3import { notFound } from 'next/navigation';4import { PageHeader } from '@/components/ui/page-header';5import { Stat } from '@/components/ui/primitives';6import { AssetBrowser } from '@/components/market/asset-browser';7import { Suspense } from 'react';8import { Skeleton } from '@/components/ui/primitives';9import { getBrandStats } from '@/lib/queries/markets';10import { catName } from '@/lib/taxonomy';11import { fmtMoney, fmtNum } from '@/lib/format';12import type { SP } from '@/lib/search-params';1314export const revalidate = 300;1516export async function generateMetadata({ params }: { params: Promise<{ brand: string }> }): Promise<Metadata> {17  const { brand } = await params;18  const name = decodeURIComponent(brand);19  return { title: `${name} collectibles`, description: `${name}: tracked collectible assets, valuations, sales and listings on RareIndex.` };20}2122export default async function BrandPage({ params, searchParams }: { params: Promise<{ brand: string }>; searchParams: Promise<SP> }) {23  const { brand } = await params;24  const sp = await searchParams;25  const name = decodeURIComponent(brand);26  const stats = await getBrandStats(name);27  if (!stats) notFound();28  return (29    <div>30      <PageHeader31        crumbs={[{ label: 'Markets', href: '/markets' }, { label: stats.brand }]}32        title={stats.brand}33        description="Brand view across every category where this brand appears."34        meta={stats.categories.map((c) => (35          <Link key={c} href={`/markets/${c}`} className="rounded-sm bg-inset px-1.5 py-0.5 hover:text-fg">36            {catName(c)}37          </Link>38        ))}39      />40      <section className="grid grid-cols-2 gap-px overflow-hidden rounded-md border border-border bg-border sm:grid-cols-3 lg:grid-cols-6">41        {[42          ['Tracked assets', fmtNum(stats.assets)],43          ['With valuation', fmtNum(stats.priced)],44          ['Sales', fmtNum(stats.sales)],45          ['Active listings', fmtNum(stats.listings)],46          ['Median RIV', stats.medianRivUsd != null ? fmtMoney(stats.medianRivUsd) : '—'],47          ['Top RIV', stats.maxRivUsd != null ? fmtMoney(stats.maxRivUsd) : '—'],48        ].map(([k, v]) => (49          <div key={k} className="bg-elevated px-3 py-2.5">50            <Stat label={k} value={v} />51          </div>52        ))}53      </section>54      <div className="mt-4">55        <Suspense fallback={<Skeleton className="h-96" />}>56          <AssetBrowser scope={{ brand: name }} sp={sp} basePath={`/brand/${brand}`} title={`${stats.brand} assets`} pageSize={60} />57        </Suspense>58      </div>59    </div>60  );61}62